﻿#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>



//const修饰
// 
// 
//int main()
//{
//	int m = 0;
//	m = 20;//m是可以修改的
//	const int n = 0;
//	n = 20;//n是不能被修改的
//
//		return 0;
//}


//代码1 -测试⽆const修饰的情况

//void test1()
//{
//	int n = 10;
//	int m = 20;
//	int* p = &n;
//	*p = 20;//ok?
//	p = &m; //ok?
//}
//
//
////代码2 -测试const放在*的左边情况
//void test2()
//{
//	int n = 10;
//	int m = 20;
//	const int* p = &n;
//	*p = 20;//ok?
//	p = &m; //ok?
//}
//
////代码3 -测试const放在*的右边情况
//
//void test3()
//{
//	int n = 10;
//	int m = 20;
//	int* const p = &n;
//	*p = 20; //ok?
//	p = &m;  //ok?
//}
//
////代码4 -测试*的左右两边都有const
//void test4()
//{
//	int n = 10;
//	int m = 20;
//	int const* const p = &n;
//	*p = 20; //ok?
//	p = &m;  //ok?
//}
//
//
//int main()
//{
//	//测试⽆	const修饰的情况
//
//		test1();
//	//测试const	放在*	的左边情况
//
//		test2();
//	//测试	const放在*的右边情况
//
//		test3();
//	//测试*的左右两边都有	const
//		test4();
//	return 0;
//}

//
//结论：const修饰指针变量的时候
//•
//const如果放在* 的左边，修饰的是指针指向的内容，保证指针指向的内容不能通过指针来改变。
//但是指针变量本⾝的内容可变

//const如果放在*的右边，修饰的是指针变量本⾝，保证了指针变量的内容不能修改，但是指针指向的内容，可以通过指针改变。



//野指针
//概念：野指针就是指针指向的位置是不可知的（随机的、不正确的、没有明确限制的）
//2.1 野指针成因
// 
// 
// 
//		1. 指针未初始化
//int main()
//{
//	int* p;//
//	局部变量指针未初始化，默认为随机值
//
//		* p = 20;
//	return 0;
//}

//2. 指针越界访问
//int main()
//{
//	int arr[10] = { 0 };
//	int* p = &arr[0];
//	int i = 0;
//	for (i = 0; i <= 11; i++)
//	{
//		*(p++) = i;
//	}
//	return 0;
//}


//3. 指针指向的空间释放
//int* test()
//{
//	int n = 100;
//	return &n;
//}
//int main()
//{
//	int* p = test();
//	printf("%d\n", *p);
//	return 0;
//}


//规避野指针
// 
// 
//2.2.1 指针初始化
//#ifdef __cplusplus
//#define NULL 0
//#else
//#define NULL (( void *)0)
//#endif

//int main()
//{
//	int num = 10;
//	int* p1 = &num;
//	int* p2 = NULL;
//	return 0;
//}

//2.2.2 ⼩⼼指针越界


//2.2.3 指针变量不再使⽤时，及时置NULL，指针使⽤之前检查有效性
//当指针变量指向⼀块区域的时候，我们可以通过指针访问该区域，后期不再使⽤这个指针访问空间的
//时候，我们可以把该指针置为NULL。因为约定俗成的⼀个规则就是：只要是NULL指针就不去访问，
//同时使⽤指针之前可以判断指针是否为NULL。
//我们可以把野指针想象成野狗，野狗放任不管是⾮常危险的，所以我们可以找⼀棵树把野狗拴起来，
//就相对安全了，给指针变量及时赋值为NULL，其实就类似把野狗栓起来，就是把野指针暂时管理起
//来。
//不过野狗即使拴起来我们也要绕着⾛，不能去挑逗野狗，有点危险；对于指针也是，在使⽤之前，我
//们也要判断是否为NULL，看看是不是被拴起来起来的野狗，如果是不能直接使⽤，如果不是我们再去
//使⽤。

//int main()
//{
//	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//	int* p = &arr[0];
//	int i = 0;
//	for (i = 0; i < 10; i++)
//	{
//		*(p++) = i;
//	}
//	//此时	p	已经越界了，可以把	p置为NULL
//		p = NULL;
//		//下次使⽤的时候，判p不为NULL的时候再使⽤
//		p = &arr[0];//重新让p获得地址
//
//		if (p != NULL) //判断
//
//		{
//			//...
//		}
//	return 0;
//}


//2.2.4 避免返回局部变量的地址





//3. assert 断⾔
//      assert.h 头⽂件定义了宏assert()，⽤于在运⾏时确保程序符合指定条件，如果不符合，就报错终⽌运⾏。这个宏常常被称为“断⾔”。
//注意有头文件



//用指针做一个自己的strlen函数
//原型
//size_t strlen(const char* str);


//int my_strlen(const char* str)//用const保证str指针变量内的内容不会被更改
//{
//	int count = 0;
//	assert(str);
//	while (*str)
//	{
//		count++;
//		str++;
//	}
//	return count;
//}
//
//int main()
//{
//	int len = my_strlen("abcdef");
//	printf("%d\n", len);
//	return 0;
//}


//传址调用与传值调用


//交换a b两值
//void Swap1(int x, int y)
//{
//	int tmp = x;
//	x = y;
//	y = tmp;
//}
//
//
//	int main()
//{
//	int a = 0;
//	int b = 0;
//	scanf("%d %d", &a, &b);
//	printf("交换前：a = % d b = % d\n", a, b);
//		Swap1(a, b);
//	printf("交换后：a = % d b = % d\n", a, b);
//		return 0;
//}
//Swap1函数在使⽤	的时候，是把变量本⾝直接传递给了函数，这种调⽤函数的⽅式我们之前在函数的时候就知道了，这种叫传值调⽤。
//这个传值是失败的，实参传递给形参的时候，形参会单独创建⼀份临时空间来接收实参，对形参的修改不影响实参
//地址会有多个，没有直接更改地址内的内容

//更改后用传址调用
//void swap2(int*px, int*py)
//{
//	int c = 0;
//	c = *px;
//	*px = *py;
//	*py = c;
//
//}
//
//int main()
//{
//	int a = 0;
//	int b = 0;
//	scanf("%d %d", &a, &b);
//	printf("交换前：a = %d ， b = %d",a,b);
//	swap2(&a,&b);
//	printf("交换后：a = %d ， b = %d", a, b);
//	return 0;
//}